# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR)
# We use the GoogleTest module if it is available (only in CMake 3.9+)
# It requires CMP0054 and CMP0057 to be enabled.
if (POLICY CMP0054)
  cmake_policy(SET CMP0054 NEW)
endif()
if (POLICY CMP0057)
  cmake_policy(SET CMP0057 NEW)
endif()

# CMP0075 Include file check macros honor CMAKE_REQUIRED_LIBRARIES
if(POLICY CMP0075)
  cmake_policy(SET CMP0075 NEW)
endif()

# includes
set(CMAKE_MODULE_PATH
  "${CMAKE_CURRENT_SOURCE_DIR}/CMake"
  ${CMAKE_MODULE_PATH})

# package information
set(PACKAGE_NAME      "melon")
if (NOT DEFINED PACKAGE_VERSION)
  set(PACKAGE_VERSION   "0.58.0-dev")
endif()
set(PACKAGE_STRING    "${PACKAGE_NAME} ${PACKAGE_VERSION}")
set(PACKAGE_TARNAME   "${PACKAGE_NAME}-${PACKAGE_VERSION}")
set(PACKAGE_BUGREPORT "https://github.com/facebook/melon/issues")
# 150+ tests in the root folder anyone? No? I didn't think so.
set_property(GLOBAL PROPERTY USE_FOLDERS ON)

project(${PACKAGE_NAME} CXX C ASM)

set(INCLUDE_INSTALL_DIR include CACHE STRING
    "The subdirectory where header files should be installed")
set(LIB_INSTALL_DIR lib CACHE STRING
    "The subdirectory where libraries should be installed")
set(BIN_INSTALL_DIR bin CACHE STRING
    "The subdirectory where binaries should be installed")
set(CMAKE_INSTALL_DIR lib/cmake/melon CACHE STRING
    "The subdirectory where CMake package config files should be installed")

option(BUILD_SHARED_LIBS
  "If enabled, build melon as a shared library.  \
  This is generally discouraged, since melon does not commit to having \
  a stable ABI."
  OFF
)
# Mark BUILD_SHARED_LIBS as an "advanced" option, since enabling it
# is generally discouraged.
mark_as_advanced(BUILD_SHARED_LIBS)
set(MELON_SUPPORT_SHARED_LIBRARY "${BUILD_SHARED_LIBS}")

option(BUILD_BENCHMARKS "If enabled, compile the benchmarks." OFF)
option(BUILD_BROKEN_TESTS "If enabled, compile tests that are known to be broken." OFF)
option(BUILD_HANGING_TESTS "If enabled, compile tests that are known to hang." OFF)
option(BUILD_SLOW_TESTS "If enabled, compile tests that take a while to run in debug mode." OFF)
option(BUILD_TESTS "If enabled, compile the tests." ON)
option(MELON_HAVE_INT128_T "If enabled, enable128 bits onpreset" ON)

if (BUILD_TESTS OR BUILD_BENCHMARKS)
  option(USE_CMAKE_GOOGLE_TEST_INTEGRATION "If enabled, use the google test integration included in CMake." ON)
  #find_package(GMock MODULE REQUIRED)
  find_package(GTest MODULE REQUIRED)
  get_target_property(GTLIB GTest::gtest IMPORT_LOCATION)
  get_target_property(GMIB  GTest::gmock IMPORT_LOCATION)
  if (USE_CMAKE_GOOGLE_TEST_INTEGRATION)
    include(GoogleTest OPTIONAL RESULT_VARIABLE HAVE_CMAKE_GTEST)
    enable_testing()
  else()
    set(HAVE_CMAKE_GTEST OFF)
  endif()
endif ()

include(KMBuildOptions)
km_activate_static_library_option()

if(NOT CMAKE_CXX_STANDARD)
  set(CMAKE_CXX_STANDARD 17)
  set(CMAKE_CXX_STANDARD_REQUIRED ON)
  message(STATUS "setting C++ standard to C++${CMAKE_CXX_STANDARD}")
endif()

if(NOT DEFINED IS_X86_64_ARCH AND ${CMAKE_SYSTEM_PROCESSOR} MATCHES "x86_64|AMD64")
  set(IS_X86_64_ARCH TRUE)
else()
  set(IS_X86_64_ARCH FALSE)
endif()

if(NOT DEFINED IS_AARCH64_ARCH AND ${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64")
  set(IS_AARCH64_ARCH TRUE)
else()
  set(IS_AARCH64_ARCH FALSE)
endif()

if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
  # Check target architecture
  if (NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
    message(FATAL_ERROR "Melon requires a 64bit target architecture.")
  endif()

  if (MSVC_VERSION LESS 1900)
    message(
      FATAL_ERROR
      "This build script only supports building Melon on 64-bit Windows with "
      "at least Visual Studio 2017. "
      "MSVC version '${MSVC_VERSION}' is not supported."
    )
  endif()
endif()

set(TOP_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set(MELON_DIR "${CMAKE_CURRENT_SOURCE_DIR}/melon")
set(
  MELON_DIR_PREFIXES
  "${CMAKE_CURRENT_SOURCE_DIR}:${CMAKE_CURRENT_BINARY_DIR}"
)

include(GNUInstallDirs)

set(CMAKE_THREAD_PREFER_PTHREAD ON)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
set(MELON_HAVE_PTHREAD "${CMAKE_USE_PTHREADS_INIT}")
list(APPEND CMAKE_REQUIRED_LIBRARIES Threads::Threads)
list(APPEND MELON_LINK_LIBRARIES Threads::Threads)

if(MSVC)
  include(MelonCompilerMSVC)
else()
  include(MelonCompilerUnix)
endif()
include(MelonFunctions)

include(melon-deps) # Find the required packages
include(MelonConfigChecks)
configure_file(
  ${CMAKE_CURRENT_SOURCE_DIR}/CMake/melon-config.h.cmake
  ${CMAKE_CURRENT_BINARY_DIR}/melon/melon-config.h
)


# We currently build the main libmelon library by finding all sources
# and header files.  We then exclude specific files below.
#
# In the future it would perhaps be nicer to explicitly list the files we want
# to include, and to move the source lists in to separate per-subdirectory
# CMakeLists.txt files.
auto_sources(files "*.cpp" "RECURSE" "${MELON_DIR}")
auto_sources(hfiles "*.h" "RECURSE" "${MELON_DIR}")

# Exclude tests, benchmarks, and other standalone utility executables from the
# library sources.  Test sources are listed separately below.
REMOVE_MATCHES_FROM_LISTS(files hfiles
  MATCHES
    "^${MELON_DIR}/build/"
    "^${MELON_DIR}/docs/examples/"
    "^${MELON_DIR}/(.*/)?test/"
    "^${MELON_DIR}/(.*/)?tool/"
    "^${MELON_DIR}/facebook/"
    "Benchmark.cpp$"
    "Test.cpp$"
    "_benchmark.cpp$"
    "_test.cpp$"
)

# Exclude exception tracer, which is necessary to statically link libstdc++
if (${MELON_NO_EXCEPTION_TRACER})
  REMOVE_MATCHES_FROM_LISTS(files hfiles
    MATCHES
      "^${MELON_DIR}/debugging/exception_tracer/"
  )
endif()

list(REMOVE_ITEM files
  ${MELON_DIR}/python/error.cpp
  ${MELON_DIR}/python/executor.cpp
  ${MELON_DIR}/python/fibers.cpp
  ${MELON_DIR}/python/GILAwareManualExecutor.cpp
  ${MELON_DIR}/python/iobuf.cpp
  ${MELON_DIR}/python/iobuf_ext.cpp
  ${MELON_DIR}/python/ProactorExecutor.cpp
)
list(REMOVE_ITEM hfiles
  ${MELON_DIR}/python/fibers.h
  ${MELON_DIR}/python/GILAwareManualExecutor.h
  ${MELON_DIR}/python/iobuf_ext.h
  ${MELON_DIR}/python/ProactorExecutor.h
)

# Explicitly include utility library code from inside
# test subdirs
list(APPEND files
  ${MELON_DIR}/io/async/test/scoped_bound_port.cpp
  ${MELON_DIR}/io/async/test/socket_pair.cpp
  ${MELON_DIR}/io/async/test/time_util.cpp
)
list(APPEND hfiles
  ${MELON_DIR}/container/test/f14_test_util.h
  ${MELON_DIR}/container/test/tracking_types.h
  ${MELON_DIR}/io/async/test/async_ssl_socket_test.h
  ${MELON_DIR}/io/async/test/async_socket_test.h
  ${MELON_DIR}/io/async/test/async_socket_test2.h
  ${MELON_DIR}/io/async/test/blocking_socket.h
  ${MELON_DIR}/io/async/test/callback_state_enum.h
  ${MELON_DIR}/io/async/test/conn_callback.h
  ${MELON_DIR}/io/async/test/mock_async_socket.h
  ${MELON_DIR}/io/async/test/mock_async_server_socket.h
  ${MELON_DIR}/io/async/test/mock_async_ssl_socket.h
  ${MELON_DIR}/io/async/test/mock_async_transport.h
  ${MELON_DIR}/io/async/test/mock_async_udp_socket.h
  ${MELON_DIR}/io/async/test/mock_timeout_manager.h
  ${MELON_DIR}/io/async/test/scoped_bound_port.h
  ${MELON_DIR}/io/async/test/socket_pair.h
  ${MELON_DIR}/io/async/test/tfo_util.h
  ${MELON_DIR}/io/async/test/test_ssl_server.h
  ${MELON_DIR}/io/async/test/time_util.h
  ${MELON_DIR}/io/async/test/undelayed_destruction.h
  ${MELON_DIR}/io/async/test/util.h
  ${MELON_DIR}/synchronization/test/semaphore.h
  ${MELON_DIR}/test/deterministic_schedule.h
  ${MELON_DIR}/test/test_utils.h
)

if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
  check_cxx_compiler_flag(-fcoroutines COMPILER_HAS_F_COROUTINES)
  if (COMPILER_HAS_F_COROUTINES)
    message(
      STATUS
      "GCC has support for C++ coroutines, setting flag for Melon build."
    )
    add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-fcoroutines>)
  else()
    message(
      STATUS
      "GCC does not have support for C++ coroutines, "
      "disabling Melon coroutine support."
    )
  endif()
endif()

# base64 SIMD files compilation
if (NOT(${IS_X86_64_ARCH}))
  message(
    STATUS
    "arch ${CMAKE_LIBRARY_ARCHITECTURE} does not match x86_64, "
    "skipping building SSE4.2 version of base64"
  )
  list(REMOVE_ITEM files ${MELON_DIR}/detail/base64_detail/base64_sse4_2.cpp)
else()
  message(
    STATUS
    "arch ${CMAKE_LIBRARY_ARCHITECTURE} matches x86_64, "
    "building SSE4.2 version of base64"
  )
  # MSVC does not have a way to enable just sse4.2, only avx.
  # If we don't pass the flag, everything will still work but no warnings
  if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
    set_source_files_properties(
      ${MELON_DIR}/detail/base64_detail/base64_sse4_2.cpp
      PROPERTIES
      COMPILE_FLAGS
        -msse4.2
    )
  endif()
endif()

if (${LIBSODIUM_FOUND})
  if (NOT(${IS_X86_64_ARCH}))
    message(
      STATUS
      "arch ${CMAKE_LIBRARY_ARCHITECTURE} does not match x86_64, "
      "skipping setting SSE2/AVX2 compile flags for LtHash SIMD code"
    )
  else()
    message(
      STATUS
      "arch ${CMAKE_LIBRARY_ARCHITECTURE} matches x86_64, "
      "setting SSE2/AVX2 compile flags for LtHash SIMD code"
    )
    set_source_files_properties(
      ${MELON_DIR}/crypto/detail/math_operation_avx2.cpp
      PROPERTIES
      COMPILE_FLAGS
      -mavx -mavx2 -msse2
    )
    set_source_files_properties(
      ${MELON_DIR}/crypto/detail/math_operation_simple.cpp
      PROPERTIES
      COMPILE_FLAGS
      -mno-avx -mno-avx2 -mno-sse2
    )
    set_source_files_properties(
      ${MELON_DIR}/crypto/detail/math_operation_sse2.cpp
      PROPERTIES
      COMPILE_FLAGS
      -mno-avx -mno-avx2 -msse2
    )
  endif()
else()
  list(REMOVE_ITEM files
    ${MELON_DIR}/crypto/blake2xb.cpp
    ${MELON_DIR}/crypto/detail/math_operation_avx2.cpp
    ${MELON_DIR}/crypto/detail/math_operation_simple.cpp
    ${MELON_DIR}/crypto/detail/math_operation_sse2.cpp
    ${MELON_DIR}/crypto/lh_hash.cpp
  )
  list(REMOVE_ITEM hfiles
    ${MELON_DIR}/crypto/blake2xb.h
    ${MELON_DIR}/crypto/detail/lt_hash_internal.h
    ${MELON_DIR}/crypto/lt_hash-inl.h
    ${MELON_DIR}/crypto/lt_hash.h
  )
endif()

if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
  list(REMOVE_ITEM files
    ${MELON_DIR}/subprocess.cpp
  )
endif()

set(PCLMUL_FILES
  ${MELON_DIR}/external/fast-crc32/avx512_crc32c_v8s3x4.cpp
  ${MELON_DIR}/external/fast-crc32/sse_crc32c_v8s3x3.cpp
  ${MELON_DIR}/hash/detail/checksum_detail.cpp
  ${MELON_DIR}/hash/detail/crc32_combine_detail.cpp
  ${MELON_DIR}/hash/detail/crc32c_detail.cpp
)
check_cxx_compiler_flag(-mpclmul COMPILER_HAS_M_PCLMUL)
if (COMPILER_HAS_M_PCLMUL)
  message(
    STATUS
    "compiler has flag pclmul, setting compile flag for ${PCLMUL_FILES}"
  )
  set_source_files_properties(
    ${PCLMUL_FILES}
    PROPERTIES
    COMPILE_OPTIONS
    -mpclmul
  )
else()
  message(
    STATUS
    "compiler does not have flag pclmul, skipping setting compile flags for ${PCLMUL_FILES}"
  )
endif()

if (IS_X86_64_ARCH AND NOT CMAKE_SYSTEM_NAME STREQUAL "Windows")
  message(
    STATUS
    "arch ${CMAKE_LIBRARY_ARCHITECTURE} matches x86_64, "
    "setting AVX512 compile flags for crc32c SIMD code"
  )
  set_property(
    SOURCE
    ${MELON_DIR}/external/fast-crc32/avx512_crc32c_v8s3x4.cpp
    APPEND PROPERTY COMPILE_OPTIONS
    "-mavx512f" "-mavx512vl"
  )
else()
  # Windows doesn't nead the extra flags.
  message(
    STATUS
    "arch ${CMAKE_LIBRARY_ARCHITECTURE} does not match x86_64, "
    "skipping setting AVX512 compile flags for crc32c SIMD code"
  )
endif()

list(APPEND melon_base_files
  ${files} ${hfiles}
)

if (IS_X86_64_ARCH AND NOT MSVC)
  set_property(
    SOURCE
    ${MELON_DIR}/memcpy.S
    APPEND PROPERTY COMPILE_OPTIONS "-x" "assembler-with-cpp"
  )
  list(APPEND melon_base_files
    ${MELON_DIR}/memcpy.S
  )
endif()

set(ARM_AOR_ASM_FILES
  ${MELON_DIR}/external/aor/memcpy-advsimd.S
  ${MELON_DIR}/external/aor/memcpy-armv8.S
  ${MELON_DIR}/external/aor/memcpy_sve.S
  ${MELON_DIR}/external/aor/memset-advsimd.S
)
if (IS_AARCH64_ARCH)
  foreach (AOR_FILE IN LISTS ARM_AOR_ASM_FILES)
    set_property(
      SOURCE
      ${AOR_FILE}
      APPEND PROPERTY COMPILE_OPTIONS "-x" "assembler-with-cpp"
    )
    list(APPEND melon_base_files
      ${AOR_FILE}
    )
  endforeach()
endif()

add_library(melon_base OBJECT
  ${melon_base_files}
  ${CMAKE_CURRENT_BINARY_DIR}/melon/melon-config.h
)
if (BUILD_SHARED_LIBS)
  set_property(TARGET melon_base PROPERTY POSITION_INDEPENDENT_CODE ON)
endif()
auto_source_group(melon ${MELON_DIR} ${files} ${hfiles})
apply_melon_compile_options_to_target(melon_base)
# Add the generated files to the correct source group.
source_group("melon" FILES ${CMAKE_CURRENT_BINARY_DIR}/melon/melon-config.h)

set(MELON_INSTALL_TARGETS melon)

option(PYTHON_EXTENSIONS
  "Build Python Bindings for Melon, requires Cython and (BUILD_SHARED_LIBS=ON)"
  OFF
)

add_library(melon
  $<TARGET_OBJECTS:melon_base>
)
set_property(TARGET melon PROPERTY VERSION ${PACKAGE_VERSION})
apply_melon_compile_options_to_target(melon)
target_compile_features(melon INTERFACE cxx_generic_lambdas)

#target_link_libraries(melon PUBLIC melon_deps)
target_link_libraries(melon PUBLIC ${DEPS_LIB})
message(STATUS  ${DEPS_LIB})

# Test utilities exported for use by downstream projects
add_library(melon_test_util
  ${MELON_DIR}/test/deterministic_schedule.cpp
  ${MELON_DIR}/json/json_test_util.cpp
)
set_property(TARGET melon_test_util PROPERTY VERSION ${PACKAGE_VERSION})
target_link_libraries(melon_test_util
  PUBLIC
    ${BOOST_LIBRARIES}
    melon
        ${GTLIB}
        ${GMIB}
)
apply_melon_compile_options_to_target(melon_test_util)
list(APPEND MELON_INSTALL_TARGETS melon_test_util)

install(TARGETS ${MELON_INSTALL_TARGETS}
  EXPORT melon
  RUNTIME DESTINATION bin
  LIBRARY DESTINATION ${LIB_INSTALL_DIR}
  ARCHIVE DESTINATION ${LIB_INSTALL_DIR})
auto_install_files(melon ${MELON_DIR}
  ${hfiles}
)
install(
  FILES ${CMAKE_CURRENT_BINARY_DIR}/melon/melon-config.h
  DESTINATION ${INCLUDE_INSTALL_DIR}/melon
  COMPONENT dev
)

# Generate the melon-config.cmake file for installation so that
# downstream projects that use on melon can easily depend on it in their CMake
# files using "find_package(melon CONFIG)"
include(CMakePackageConfigHelpers)
configure_package_config_file(
  CMake/melon-config.cmake.in
  melon-config.cmake
  INSTALL_DESTINATION ${CMAKE_INSTALL_DIR}
  PATH_VARS
    INCLUDE_INSTALL_DIR
    CMAKE_INSTALL_DIR
)
install(
  FILES ${CMAKE_CURRENT_BINARY_DIR}/melon-config.cmake
  DESTINATION ${CMAKE_INSTALL_DIR}
  COMPONENT dev
)
install(
  EXPORT melon
  DESTINATION ${CMAKE_INSTALL_DIR}
  NAMESPACE Melon::
  FILE melon-targets.cmake
  COMPONENT dev
)

# Generate a pkg-config file so that downstream projects that don't use
# CMake can depend on melon using pkg-config.
configure_file(
  ${CMAKE_CURRENT_SOURCE_DIR}/CMake/libmelon.pc.in
  ${CMAKE_CURRENT_BINARY_DIR}/libmelon.pc.gen
  @ONLY
)
include_directories(${CMAKE_BINARY_DIR})
include_directories(${CMAKE_SOURCE_DIR})
# Specify target to allow resolving generator expressions requiring
# a target for CMake >=3.19. See #1414.
# VERSION_GREATER_EQUAL isn't available before CMake 3.7.
#[[
if(NOT CMAKE_VERSION VERSION_LESS 3.19)
  set(target_arg TARGET melon_deps)
endif()
]]
file(
  GENERATE
  OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/libmelon.pc
  INPUT ${CMAKE_CURRENT_BINARY_DIR}/libmelon.pc.gen
  ${target_arg}
)
install(
  FILES ${CMAKE_CURRENT_BINARY_DIR}/libmelon.pc
  DESTINATION ${LIB_INSTALL_DIR}/pkgconfig
  COMPONENT dev
)

if (BUILD_TESTS OR BUILD_BENCHMARKS)
  # The ThreadLocalTest code uses a helper shared library for one of its tests.
  # This can only be built if melon itself was built as a shared library.
  if (BUILD_SHARED_LIBS)
    add_library(thread_local_test_lib MODULE
      ${MELON_DIR}/test/thread_local_test_lib.cpp
    )
    set_target_properties(thread_local_test_lib PROPERTIES PREFIX "")
    apply_melon_compile_options_to_target(thread_local_test_lib)
    target_link_libraries(thread_local_test_lib PUBLIC melon)
    target_include_directories(
      thread_local_test_lib
      PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
  endif()

  add_library(melon_test_support
    ${MELON_DIR}/test/common/test_main.cpp
    ${MELON_DIR}/test/kmvector_test_util.cpp
    ${MELON_DIR}/test/deterministic_schedule.cpp
    ${MELON_DIR}/test/deterministic_schedule.h
    ${MELON_DIR}/test/singleton_test_structs.cpp
    ${MELON_DIR}/test/socket_address_test_helper.cpp
    ${MELON_DIR}/test/socket_address_test_helper.h
    ${MELON_DIR}/compression/test/coding_test_utils.cpp
    ${MELON_DIR}/container/test/f14_test_util.h
    ${MELON_DIR}/container/test/tracking_types.h
    ${MELON_DIR}/futures/test/test_executor.cpp
    ${MELON_DIR}/futures/test/test_executor.h
    ${MELON_DIR}/io/async/test/blocking_socket.h
    ${MELON_DIR}/io/async/test/callback_state_enum.h
    ${MELON_DIR}/io/async/test/conn_callback.h
    ${MELON_DIR}/io/async/test/mock_async_server_socket.h
    ${MELON_DIR}/io/async/test/mock_async_socket.h
    ${MELON_DIR}/io/async/test/mock_async_ssl_socket.h
    ${MELON_DIR}/io/async/test/mock_async_transport.h
    ${MELON_DIR}/io/async/test/mock_async_udp_socket.h
    ${MELON_DIR}/io/async/test/mock_timeout_manager.h
    ${MELON_DIR}/io/async/test/scoped_bound_port.cpp
    ${MELON_DIR}/io/async/test/scoped_bound_port.h
    ${MELON_DIR}/io/async/test/socket_pair.cpp
    ${MELON_DIR}/io/async/test/socket_pair.h
    ${MELON_DIR}/io/async/test/ssl_util.cpp
    ${MELON_DIR}/io/async/test/ssl_util.h
    ${MELON_DIR}/io/async/test/tfo_util.cpp
    ${MELON_DIR}/io/async/test/tfo_util.h
    ${MELON_DIR}/io/async/test/test_ssl_server.cpp
    ${MELON_DIR}/io/async/test/test_ssl_server.h
    ${MELON_DIR}/io/async/test/time_util.cpp
    ${MELON_DIR}/io/async/test/time_util.h
    ${MELON_DIR}/io/async/test/undelayed_destruction.h
    ${MELON_DIR}/io/async/test/util.h
  )

  target_include_directories(melon_test_support
    SYSTEM
    PUBLIC
      ${LIBGMOCK_INCLUDE_DIR}
      ${GTEST_INCLUDE_DIRS}
  )
  target_link_libraries(melon_test_support
    PUBLIC
      ${BOOST_LIBRARIES}
      melonbenchmark
      melon
          ${GTLIB}
          ${GMIB}
      ${GLOG_LIBRARY}
  )
  apply_melon_compile_options_to_target(melon_test_support)
  set(GTEST_LIBS
          ${GTLIB}
          ${GMIB}
          )
  melon_define_tests(
    DIRECTORY algorithm/simd/detail/test/
      TEST simd_any_of_test SOURCES simd_any_of_test.cpp
      TEST unroll_utils_test SOURCES unroll_utils_test.cpp
      TEST simd_for_each_test SOURCES simd_for_each_test.cpp

    DIRECTORY algorithm/simd/test/
      TEST find_fixed_test SOURCES find_fixed_test.cpp
      TEST movemask_test SOURCES movemask_test.cpp

    DIRECTORY chrono/test/
      TEST chrono_conv_test WINDOWS_DISABLED
        SOURCES conv_test.cpp

    DIRECTORY compression/test/
      TEST compression_test SLOW SOURCES compression_test.cpp
      TEST quotient_multiset_test SOURCES quotient_multi_set_test.cpp
      TEST select64_test SOURCES select64_test.cpp

    DIRECTORY compression/elias_fano/test/
      TEST bitvector_test SOURCES bit_vector_coding_test.cpp
      TEST eliasfano_test SOURCES elias_fano_coding_test.cpp

    DIRECTORY container/test/
      TEST access_test SOURCES access_test.cpp
      TEST array_test SOURCES array_test.cpp
      BENCHMARK bit_iterator_benchmark SOURCES bit_iterator_bench.cpp
      TEST bit_iterator_test SOURCES bit_iterator_test.cpp
      TEST enumerate_test SOURCES enumerate_test.cpp
      BENCHMARK evicting_cache_map_benchmark SOURCES evicting_cache_map_bench.cpp
      TEST evicting_cache_map_test SOURCES evicting_cache_map_test.cpp
      TEST f14_fwd_test SOURCES f14_fwd_test.cpp
      TEST f14_map_test SOURCES f14_map_test.cpp
      TEST f14_set_test WINDOWS_DISABLED SOURCES f14_set_test.cpp
      BENCHMARK kmvector_benchmark
        SOURCES kmvector_benchmark.cpp
        HEADERS kmvector_benchmarks.cpp.h
      TEST kmvector_test SOURCES kmvector_test.cpp
      BENCHMARK foreach_benchmark SOURCES foreach_benchmark.cpp
      TEST foreach_test SOURCES foreach_test.cpp
      TEST heap_vector_types_test SOURCES heap_vector_types_test.cpp
      TEST map_util_test WINDOWS_DISABLED SOURCES map_util_test.cpp
      TEST merge_test SOURCES merge_test.cpp
      TEST small_vector_test WINDOWS_DISABLED
        SOURCES small_vector_test.cpp
      TEST sorted_vector_types_test SOURCES sorted_vector_test.cpp
      BENCHMARK sparse_byte_set_benchmark WINDOWS_DISABLED
        SOURCES sparse_byte_set_benchmark.cpp
      TEST sparse_byte_set_test SOURCES sparse_byte_set_test.cpp
      TEST util_test SOURCES util_test.cpp

    DIRECTORY concurrency/container/test/
      TEST lock_free_ring_buffer_test SOURCES lock_free_ring_buffer_test.cpp

    DIRECTORY concurrency/test/
      TEST atomic_shared_ptr_test SOURCES atomic_shared_ptr_test.cpp
      TEST cache_locality_test WINDOWS_DISABLED SOURCES cache_locality_test.cpp
      TEST core_cached_shared_ptr_test SOURCES core_cached_shared_ptr_test.cpp
      BENCHMARK concurrent_hash_map_benchmark WINDOWS_DISABLED
        SOURCES concurrent_hash_map_bench.cpp
      TEST concurrent_hash_map_test WINDOWS_DISABLED
        SOURCES concurrent_hash_map_test.cpp
      TEST dynamic_bounded_queue_test WINDOWS_DISABLED
        SOURCES dynamic_bounded_queue_test.cpp
      TEST priority_unbounded_queue_set_test
        SOURCES priority_unbounded_queue_set_test.cpp
      BENCHMARK thread_cached_synchronized_benchmark
        SOURCES thread_cached_synchronized_bench.cpp
      TEST thread_cached_synchronized_test
        SOURCES thread_cached_synchronized_test.cpp
      TEST unbounded_queue_test SOURCES unbounded_queue_test.cpp

    DIRECTORY detail/test/
      TEST static_singleton_manager_test SOURCES static_singleton_manager_test.cpp

    DIRECTORY detail/test/
      TEST simple_simd_string_utils_test SOURCES simple_simd_string_utils_test.cpp

    DIRECTORY detail/test/
      TEST split_string_simd_test WINDOWS_DISABLED
        SOURCES split_string_simd_test.cpp

    DIRECTORY detail/base64_detail/tests/
      TEST base64_detail_test WINDOWS_DISABLED
      SOURCES
        base64_against_scalar_test.cpp
        base64_platform_test.cpp
        base64_special_cases_test.cpp

    DIRECTORY executors/test/
      TEST async_helpers_test SOURCES async_test.cpp
      TEST codel_test WINDOWS_DISABLED SOURCES codel_test.cpp
      BENCHMARK edf_thread_pool_executor_benchmark
        SOURCES edf_thread_pool_executor_benchmark.cpp
      TEST executor_test SOURCES executor_test.cpp
      TEST fiber_io_executor_test SOURCES fiber_io_executor_test.cpp
      # FunctionSchedulerTest has a lot of timing-dependent checks,
      # and tends to fail on heavily loaded systems.
      TEST function_scheduler_test BROKEN SOURCES function_scheduler_test.cpp
      TEST global_executor_test SOURCES global_executor_test.cpp
      TEST serial_executor_test SOURCES serial_executor_test.cpp
      # Fails in ThreadPoolExecutorTest.RequestContext:719 data2 != nullptr
      TEST thread_pool_executor_test BROKEN WINDOWS_DISABLED
        SOURCES thread_pool_executor_test.cpp
      TEST threaded_executor_test SOURCES threaded_executor_test.cpp
      TEST timed_drivable_executor_test SOURCES timed_drivable_executor_test.cpp

    DIRECTORY executors/task_queue/test/
      TEST priority_unbounded_blocking_queue_test
        SOURCES priority_unbounded_blocking_queue_test.cpp
      BENCHMARK unbounded_blocking_queue_benchmark
        SOURCES unbounded_blocking_queue_bench.cpp
      TEST unbounded_blocking_queue_test SOURCES unbounded_blocking_queue_test.cpp

    #DIRECTORY experimental/test/
      #TEST nested_command_line_app_test SOURCES nested_command_line_app_test.cpp
      #TEST program_options_test SOURCES program_options_test.cpp
      # Depends on liburcu
      #TEST read_mostly_shared_ptr_test SOURCES read_mostly_shared_ptr_test.cpp
      #TEST ref_count_test SOURCES ref_count_test.cpp

    #DIRECTORY experimental/io/test/

    DIRECTORY external/farmhash/test/
      TEST farmhash_test SOURCES farmhash_test.cpp


    DIRECTORY fibers/test/
      # FiberManager swapWithException fails with segfault
      BENCHMARK fibers_benchmark WINDOWS_DISABLED
        SOURCES fibers_benchmark.cpp
      TEST fibers_test BROKEN SOURCES fibers_test.cpp

    DIRECTORY functional/test/
      TEST apply_tuple_test WINDOWS_DISABLED
        SOURCES apply_tuple_test.cpp
      TEST functional_invoke_test WINDOWS_DISABLED
        SOURCES invoke_test.cpp
      TEST partial_test SOURCES partial_test.cpp
      TEST functional_protocol_test SOURCES protocol_test.cpp
      TEST functional_traits_test SOURCES traits_test.cpp

    DIRECTORY futures/test/
      TEST barrier_test SOURCES barrier_test.cpp
      TEST callback_lifetime_test SOURCES callback_lifetime_test.cpp
      TEST collect_test SOURCES collect_test.cpp
      TEST context_test SOURCES context_test.cpp
      TEST core_test SOURCES core_test.cpp
      TEST ensure_test SOURCES ensure_test.cpp
      TEST filter_test SOURCES filter_test.cpp
      TEST future_splitter_test SOURCES future_splitter_test.cpp
      BENCHMARK futures_benchmark WINDOWS_DISABLED
        SOURCES benchmark.cpp
      TEST future_test WINDOWS_DISABLED
        SOURCES future_test.cpp
      TEST header_compile_test SOURCES header_compile_test.cpp
      TEST interrupt_test SOURCES interrupt_test.cpp
      TEST map_test SOURCES map_test.cpp
      TEST non_copyable_lambda_test SOURCES non_copyable_lambda_test.cpp
      TEST poll_test SOURCES poll_test.cpp
      TEST promise_test SOURCES promise_test.cpp
      TEST reduce_test SOURCES reduce_test.cpp
      TEST retrying_test SOURCES retrying_test.cpp
      TEST self_destruct_test SOURCES self_destruct_test.cpp
      TEST shared_promise_test SOURCES shared_promise_test.cpp
      TEST test_executor_test SOURCES test_executor_test.cpp
      TEST then_compile_test
        HEADERS
          then_compile_test.h
        SOURCES
          then_compile_test.cpp
      TEST then_test SOURCES then_test.cpp
      TEST timekeeper_test WINDOWS_DISABLED SOURCES timekeeper_test.cpp
      TEST times_test SOURCES times_test.cpp
      TEST unwrap_test SOURCES unwrap_test.cpp
      TEST via_test SOURCES via_test.cpp
      TEST wait_test SOURCES wait_test.cpp
      TEST when_test SOURCES when_test.cpp
      TEST while_do_test SOURCES while_do_test.cpp
      TEST will_equal_test SOURCES will_equal_test.cpp
      TEST window_test WINDOWS_DISABLED
        SOURCES window_test.cpp

    DIRECTORY gen/test/
      # MSVC bug can't resolve initializer_list constructor properly
      #TEST base_test SOURCES base_test.cpp
      TEST combine_test SOURCES combine_test.cpp
      BENCHMARK parallel_map_benchmark SOURCES parallel_map_benchmark.cpp
      TEST parallel_map_test SOURCES parallel_map_test.cpp
      BENCHMARK parallel_benchmark SOURCES parallel_benchmark.cpp
      TEST parallel_test SOURCES parallel_test.cpp

    DIRECTORY hash/test/
      BENCHMARK checksum_benchmark SOURCES checksum_benchmark.cpp
      TEST checksum_test SOURCES checksum_test.cpp
      TEST farm_hash_test SOURCES farm_hash_test.cpp
      BENCHMARK hash_benchmark WINDOWS_DISABLED
        SOURCES hash_benchmark.cpp
      TEST hash_test WINDOWS_DISABLED
        SOURCES hash_test.cpp
      TEST spooky_hash_v1_test SOURCES spooky_hash_v1_test.cpp
      TEST spooky_hash_v2_test SOURCES spooky_hash_v2_test.cpp

    DIRECTORY io/test/
      TEST fs_util_test SOURCES fs_util_test.cpp
      TEST iobuf_test WINDOWS_DISABLED SOURCES io_buf_test.cpp
      TEST iobuf_cursor_test SOURCES io_buf_cursor_test.cpp
      TEST iobuf_queue_test SOURCES io_buf_queue_test.cpp
      TEST record_io_test WINDOWS_DISABLED SOURCES record_io_test.cpp
      TEST ShutdownSocketSetTest HANGING
        SOURCES shutdown_socket_set_test.cpp
      TEST SocketOptionValueTest HANGING
        SOURCES socket_option_value_test.cpp

    DIRECTORY io/async/test/
      # A number of tests in the async_test binary are unfortunately flaky.
      # When run under Travis CI a number of the tests also hang (it looks
      # like they do not get expected socket accept events, causing them
      # to never break out of their event loops).
      TEST async_test BROKEN
        CONTENT_DIR certs/
        HEADERS
          async_socket_test.h
          async_ssl_socket_test.h
        SOURCES
          async_pipe_test.cpp
          async_socket_exception_test.cpp
          async_socket_test.cpp
          async_socket_test2.cpp
          async_ssl_socket_test.cpp
          async_ssl_socket_test2.cpp
          async_ssl_socket_write_test.cpp
          async_transport_test.cpp
          # This is disabled because it depends on things that don't exist
          # on Windows.
          #event_handler_test.cpp
          # The async signal handler is not supported on Windows.
          #async_signal_handler_test.cpp
      TEST async_timeout_test SOURCES async_timeout_test.cpp
      TEST AsyncUDPSocketTest APPLE_DISABLED WINDOWS_DISABLED
        SOURCES async_udp_socket_test.cpp
      TEST DelayedDestructionTest SOURCES delayed_destruction_test.cpp
      TEST DelayedDestructionBaseTest SOURCES delayed_destruction_base_test.cpp
      TEST DestructorCheckTest SOURCES destructor_check_test.cpp
      # Fails with gtest macro error
      TEST EventBaseTest BROKEN SOURCES event_base_test.cpp
      TEST EventBaseLocalTest WINDOWS_DISABLED SOURCES event_base_local_test.cpp
      TEST HHWheelTimerTest SOURCES hh_wheel_timer_test.cpp
      TEST HHWheelTimerSlowTests SLOW
        SOURCES HHWheelTimerSlowTests.cpp
      TEST NotificationQueueTest WINDOWS_DISABLED
        SOURCES notification_queue_test.cpp
      BENCHMARK request_context_benchmark WINDOWS_DISABLED
        SOURCES request_context_benchmark.cpp
        HEADERS request_context_helper.h
      TEST RequestContextTest WINDOWS_DISABLED SOURCES request_context_test.cpp
      TEST ScopedEventBaseThreadTest WINDOWS_DISABLED
        SOURCES scoped_event_base_thread_test.cpp
      TEST ssl_session_test
        CONTENT_DIR certs/
        SOURCES ssl_session_test.cpp
      TEST writechain_test SOURCES write_chain_async_transport_wrapper_test.cpp

    DIRECTORY io/async/ssl/test/
      TEST ssl_errors_test SOURCES ssl_errors_test.cpp

    DIRECTORY lang/test/
      TEST lang_align_test SOURCES align_test.cpp
      TEST lang_aligned_test SOURCES aligned_test.cpp
      TEST lang_badge_test SOURCES badge_test.cpp
      TEST lang_bits_class_test SOURCES bits_class_test.cpp
      TEST lang_bits_test SOURCES bits_test.cpp
      TEST lang_c_string_test SOURCES cstring_test.cpp
      TEST lang_cast_test SOURCES cast_test.cpp
      TEST lang_checked_math_test SOURCES checked_math_test.cpp
      TEST lang_exception_test SOURCES exception_test.cpp
      TEST lang_extern_test SOURCES extern_test.cpp
      TEST lang_ordering_test SOURCES ordering_test.cpp
      TEST lang_pretty_test SOURCES pretty_test.cpp
      TEST lang_propagate_const_test SOURCES propagate_const_test.cpp
      TEST lang_r_value_reference_wrapper_test WINDOWS_DISABLED
        SOURCES rvalue_reference_wrapper_test.cpp
      TEST lang_safe_assert_test SOURCES safe_assert_test.cpp
      BENCHMARK lang_to_ascii_benchmark SOURCES to_ascii_bench.cpp
      TEST lang_to_ascii_test SOURCES to_ascii_test.cpp
      TEST lang_type_info_test SOURCES type_info_test.cpp

    DIRECTORY memory/test/
      TEST arena_test WINDOWS_DISABLED SOURCES arena_test.cpp
      TEST reentrant_allocator_test WINDOWS_DISABLED
        SOURCES reentrant_allocator_test.cpp
      TEST thread_cached_arena_test WINDOWS_DISABLED
        SOURCES thread_cached_arena_test.cpp
      TEST mallctl_helper_test SOURCES mallctl_helper_test.cpp
      TEST uninitialized_memory_hacks_test
        SOURCES uninitialized_memory_hacks_test.cpp

    DIRECTORY net/detail/test/
      TEST socket_file_descriptor_map_test SOURCES socket_file_descriptor_map_test.cpp

    DIRECTORY portability/test/
      TEST constexpr_test SOURCES constexpr_test.cpp
      TEST filesystem_test SOURCES filesystem_test.cpp
      TEST libgen-test SOURCES libgen_test.cpp
      TEST openssl_portability_test SOURCES openssl_portability_test.cpp
      TEST pthread_test SOURCES pthread_test.cpp
      TEST time-test WINDOWS_DISABLED
        SOURCES time_test.cpp

    DIRECTORY ssl/test/
      TEST openssl_hash_test SOURCES openssl_hash_test.cpp

    DIRECTORY stats/test/
      TEST buffered_stat_test SOURCES buffered_stat_test.cpp
      BENCHMARK digest_builder_benchmark SOURCES digest_builder_benchmark.cpp
      TEST digest_builder_test SOURCES digest_builder_test.cpp
      BENCHMARK histogram_benchmark SOURCES histogram_benchmark.cpp
      TEST histogram_test SOURCES histogram_test.cpp
      BENCHMARK quantile_histogram_benchmark
        SOURCES quantile_histogram_benchmark.cpp
      TEST quantile_estimator_test SOURCES quantile_estimator_test.cpp
      TEST sliding_window_test SOURCES sliding_window_test.cpp
      BENCHMARK tdigest_benchmark SOURCES tdigest_benchmark.cpp
      TEST tdigest_test SOURCES tdigest_test.cpp
      TEST timeseries_histogram_test SOURCES timeseries_histogram_test.cpp
      TEST timeseries_test SOURCES time_series_test.cpp

    DIRECTORY synchronization/test/
      BENCHMARK baton_benchmark SOURCES baton_benchmark.cpp
      TEST baton_test SOURCES baton_test.cpp
      TEST call_once_test SOURCES call_once_test.cpp
      TEST event_count_test SOURCES event_count_test.cpp
      TEST lifo_sem_test WINDOWS_DISABLED SOURCES lifo_sem_tests.cpp
      TEST relaxed_atomic_test WINDOWS_DISABLED SOURCES relaxed_atomic_test.cpp
      TEST rw_spin_lock_test SOURCES rw_spinlock_test.cpp
      TEST semaphore_test WINDOWS_DISABLED SOURCES semaphore_test.cpp

    DIRECTORY synchronization/detail/test/
      TEST hardware_test SOURCES hardware_test.cpp

    DIRECTORY system/test/
      TEST memory_mapping_test SOURCES memory_mapping_test.cpp
      TEST shell_test SOURCES shell_test.cpp
      #TEST subprocess_test SOURCES subprocess_test.cpp
      TEST thread_id_test SOURCES thread_id_test.cpp
      TEST thread_name_test WINDOWS_DISABLED
        SOURCES thread_name_test.cpp

    DIRECTORY synchronization/test/
      TEST atomic_struct_test SOURCES atomic_struct_test.cpp
      TEST small_locks_test SOURCES small_locks_test.cpp
      TEST atomic_util_test SOURCES atomic_util_test.cpp

    DIRECTORY test/
      TEST auto_timer_test SOURCES auto_timer_test.cpp
      TEST ahm_int_stress_test SOURCES ahm_int_stress_test.cpp
      TEST arena_smartptr_test SOURCES arena_smart_ptr_test.cpp
      BENCHMARK ascii_case_insensitive_benchmark
        SOURCES ascii_case_insensitive_benchmark.cpp
      TEST ascii_check_test SOURCES ascii_case_insensitive_test.cpp
      TEST atomic_hash_array_test SOURCES atomic_hash_array_test.cpp
      TEST atomic_hash_map_test HANGING
        SOURCES atomic_hash_map_test.cpp
      TEST atomic_linked_list_test SOURCES atomic_linked_list_test.cpp
      TEST atomic_unordered_map_test SOURCES atomic_unordered_map_test.cpp
      TEST base64_test SOURCES base64_test.cpp
      TEST clock_gettime_wrappers_test SOURCES clock_gettime_wrappers_test.cpp
      TEST concurrent_bit_set_test SOURCES concurrent_bitset_test.cpp
      BENCHMARK concurrent_skip_list_benchmark
        SOURCES concurrent_skiplist_benchmark.cpp
      TEST concurrent_skip_list_test SOURCES concurrent_skiplist_test.cpp
      TEST constexpr_math_test WINDOWS_DISABLED
        SOURCES constexpr_math_test.cpp
      TEST conv_test WINDOWS_DISABLED SOURCES conv_test.cpp
      TEST cpu_id_test SOURCES cpu_id_test.cpp
      TEST demangle_test SOURCES demangle_test.cpp
      TEST deterministic_schedule_test SOURCES deterministic_schedule_test.cpp
      TEST discriminated_ptr_test SOURCES discriminated_ptr_test.cpp
      TEST endian_test SOURCES endian_test.cpp
      TEST exception_test SOURCES exception_test.cpp
      BENCHMARK exception_wrapper_benchmark WINDOWS_DISABLED
        SOURCES exception_wrapper_benchmark.cpp
      TEST exception_wrapper_test WINDOWS_DISABLED
        SOURCES exception_wrapper_test.cpp
      TEST expected_test WINDOWS_DISABLED
        SOURCES expected_test.cpp
      BENCHMARK kmstring_benchmark WINDOWS_DISABLED
        SOURCES kmstring_benchmark.cpp
        HEADERS kmstring_test_benchmarks.cpp.h
      TEST kmstring_test WINDOWS_DISABLED SOURCES kmstring_test.cpp
      TEST file_test SOURCES file_test.cpp
      # Open-source linux build can't handle running this.
      #TEST file_lock_test SOURCES file_lock_test.cpp
      TEST file_util_test SOURCES file_util_test.cpp
      BENCHMARK fingerprint_benchmark SOURCES fingerprint_benchmark.cpp
      TEST fingerprint_test SOURCES fingerprint_test.cpp
      TEST fixed_string_test SOURCES fixed_string_test.cpp
      TEST format_other_test SOURCES format_other_test.cpp
      BENCHMARK format_benchmark SOURCES format_benchmark.cpp
      TEST format_test SOURCES format_test.cpp
      TEST function_test BROKEN
        SOURCES function_test.cpp
      BENCHMARK function_ref_benchmark SOURCES function_ref_benchmark.cpp
      TEST function_ref_test SOURCES function_ref_test.cpp
      TEST futex_test SOURCES futex_test.cpp
      TEST group_varint_test SOURCES group_varint_test.cpp
      TEST group_varint_test_ssse3 SOURCES group_varint_test.cpp
      TEST iterators_test SOURCES iterators_test.cpp
      TEST indestructible_test SOURCES indestructible_test.cpp
      TEST indexed_mem_pool_test BROKEN
        SOURCES indexed_mem_pool_test.cpp
      TEST lazy_test SOURCES lazy_test.cpp
      TEST locks_test SOURCES spinlock_test.cpp
      TEST math_test SOURCES math_test.cpp
      TEST memcpy_test SOURCES memcpy_test.cpp
      TEST memory_idler_test SOURCES memory_idler_test.cpp
      TEST memory_test WINDOWS_DISABLED
        SOURCES memory_test.cpp
      TEST move_wrapper_test SOURCES move_wrapper_test.cpp
      TEST mpmc_pipeline_test SOURCES mpmc_pipeline_test.cpp
      TEST mpmc_queue_test SLOW
        SOURCES mpmpc_queue_test.cpp
      TEST network_address_test HANGING
        SOURCES
          ip_address_test.cpp
          mac_address_test.cpp
          socket_address_test.cpp
      TEST optional_test SOURCES optional_test.cpp
      TEST packed_sync_ptr_test HANGING
        SOURCES packed_sync_ptr_test.cpp
      TEST padded_test SOURCES padded_test.cpp
      #TEST poly_test SOURCES poly_test.cpp
      TEST portability_test SOURCES portability_test.cpp
      # Turns out this benchmark uses Linux only API for setting CPU affinity i.e. cpu_set_t.
      BENCHMARK producer_consumer_queue_benchmark APPLE_DISABLED WINDOWS_DISABLED
        SOURCES producer_consumer_queue_benchmark.cpp
      TEST producer_consumer_queue_test SLOW
        SOURCES producer_consumer_queue_test.cpp
      BENCHMARK range_find_benchmark SOURCES range_find_benchmark.cpp
      TEST random_test SOURCES random_test.cpp
      TEST range_test SOURCES range_test.cpp
      TEST replaceable_test WINDOWS_DISABLED SOURCES replaceable_test.cpp
      TEST scope_guard_test WINDOWS_DISABLED SOURCES scope_guard_test.cpp
      # Heavily dependent on drand and srand48
      #TEST shared_mutex_test SOURCES shared_mutex_test.cpp
      # SingletonTest requires Subprocess
      #TEST singleton_test SOURCES singleton_test.cpp
      TEST singleton_test_global SOURCES singleton_test_global.cpp
      BENCHMARK string_benchmark WINDOWS_DISABLED SOURCES string_benchmark.cpp
      TEST string_test WINDOWS_DISABLED SOURCES string_test.cpp
      BENCHMARK synchronized_benchmark WINDOWS_DISABLED
        SOURCES synchronized_benchmark.cpp
      TEST synchronized_test WINDOWS_DISABLED
        SOURCES synchronized_test.cpp
      TEST thread_cached_int_test WINDOWS_DISABLED
        SOURCES thread_cached_int_test.cpp
      TEST thread_local_test WINDOWS_DISABLED SOURCES thread_local_test.cpp
      TEST timeout_queue_test SOURCES timeout_queue_test.cpp
      TEST token_bucket_test SOURCES token_bucket_test.cpp
      TEST traits_test SOURCES traits_test.cpp
      TEST try_test WINDOWS_DISABLED SOURCES try_test.cpp
      TEST unit_test SOURCES unit_test.cpp
      BENCHMARK uri_benchmark SOURCES uri_benchmark.cpp
      TEST uri_test SOURCES uri_test.cpp
      TEST varint_test SOURCES varint_test.cpp

    DIRECTORY testing/test/
      TEST test_util_test SOURCES test_util_test.cpp

    DIRECTORY json/test/
      TEST dynamic_converter_test SOURCES dynamic_converter_test.cpp
      TEST dynamic_other_test SOURCES dynamic_other_test.cpp
      TEST dynamic_parser_test SOURCES dynamic_parser_test.cpp
      TEST dynamic_test SOURCES dynamic_test.cpp
      # MSVC Preprocessor stringizing raw string literals bug
      TEST json_test WINDOWS_DISABLED SOURCES json_test.cpp
      BENCHMARK json_benchmark SOURCES json_benchmark.cpp
      TEST json_other_test SOURCES json_other_test.cpp
      TEST json_patch_test SOURCES json_patch_test.cpp
      TEST json_pointer_test SOURCES json_pointer_test.cpp
      TEST json_schema_test SOURCES json_schema_test.cpp
  )

  if (${LIBSODIUM_FOUND})
    melon_define_tests(
      DIRECTORY crypto/test/
        TEST blake2xb_test SOURCES blake2xb_test.cpp
        TEST lt_hash_test SOURCES lt_hash_test.cpp
    )
  endif()

  if (${LIBAIO_FOUND})
    melon_define_tests(
      DIRECTORY io/async/test/
        TEST async_io_test
          SOURCES
            async_io_test.cpp
            async_base_test_lib.cpp
            io_test_temp_file_util.cpp
    )
  endif()

  get_target_property(pic melon POSITION_INDEPENDENT_CODE)
  if (pic)
    add_library(singleton_thread_local_overload
      SHARED ${MELON_DIR}/test/SingletonThreadLocalTestOverload.cpp)
    apply_melon_compile_options_to_target(singleton_thread_local_overload)
    set_target_properties(singleton_thread_local_overload PROPERTIES PREFIX "")
    target_link_libraries(singleton_thread_local_overload PRIVATE melon)
    melon_define_tests(
      DIRECTORY test/
        TEST singleton_thread_local_test SOURCES singleton_thread_local_test.cpp
    )
  endif()
endif()

add_subdirectory(melon)
